package jt

// jt808 2013
import (
	"bytes"
	"errors"
	"fmt"
	"log"
	"time"

	"github.com/dontls/xproto"
)

func init() {
	xproto.Register("jt", NewClient)
}

type terminalKey struct {
	Property   uint16
	Upgrade    uint16
	Localtion  uint16
	OnDemand   uint16
	AVProperty uint16
}

// Client jt8080
type Client struct {
	*xproto.Conn

	Msg      jtMsgPacket
	jtBytes  *jtBytes
	terminal *jtRegister
	sequence uint16
	key      terminalKey
	lstAlarm uint32
	cAlarmTs [32]string // 缓存告警时间
}

// isValid 协议判断
func isValid(b []byte) (int, error) {
	if len(b) < jtHeaderLength {
		return -1, nil
	}
	if b[0] != jtFlag {
		return -1, errors.New("invalid jt protocol")
	}
	return bytes.IndexByte(b[1:], jtFlag) + 1, nil
}

func (c *Client) resultKey(sequence uint16) string {
	if sequence == 0 {
		return "ok"
	}
	return fmt.Sprintf("%s-%d", c.DeviceNo, sequence)
}

// writeMessage 发送消息
func (c *Client) WriteMessage(msgID uint16, b []byte) error {
	rdata := c.jtPacketBytes(msgID, b)
	return c.Conn.WriteBytes(rdata)
}

// WriteAck 通用应答
// 0 success; 1 failed; 2 message error;3 unsupport;4 alarm
func (c *Client) WriteAck(result uint8) error {
	var data jtBytes
	data.addWord(c.Msg.SerialNum)
	data.addWord(c.Msg.ID)
	data.addByte(result)
	return c.WriteMessage(0x8001, data.Bytes)
}

// phoneNumber 设备号
func (c *Client) phoneNumber() string {
	s, size := "", len(c.Msg.PhoneNumberBcd)
	for i, v := range c.Msg.PhoneNumberBcd {
		if s == "" && (size-i) > 3 && c.Msg.PhoneNumberBcd[i] == 0 {
			continue
		}
		s += fmt.Sprintf("%02X", v)
	}
	return s
}

func NewClient(c *xproto.Conn) xproto.IClient {
	if l, _ := isValid(c.Body()); l < 0 {
		return nil
	}
	c.LinkType = xproto.LinkUnknow
	return &Client{Conn: c}
}

// OnHandler 协议解析回调
func (c *Client) OnHandler(b []byte) (int, error) {
	p0, err := isValid(b)
	if err != nil || p0 < 1 {
		return 0, err
	}
	c.jtBytes = c.Msg.Unmarshal(b[1:p0])
	log.Printf("code 0x%04x, body length %d\n", c.Msg.ID, len(c.Msg.Data))
	switch c.Msg.ID {
	case 0x0001:
		c.onRecvResp()
	case 0x0002: // heartbeat
		c.WriteAck(0)
	case 0x0004:
		c.onRecvQueryTime()
	case 0x0100:
		err = c.onRevRegister()
	case 0x0102:
		c.onRecvAuthority()
	case 0x0104:
		c.onRecvParameters()
	case 0x0107:
		c.OnRecvTerminalProperty()
	case 0x0108:
		c.OnRecvTerminalUpgrade()
	case 0x0200:
		c.onRecvLoStatus()
	case 0x0201:
		c.onRecvQueryLocation()
	case 0x0302:
		c.onRecvAnswer()
	case 0x0303:
		c.onRecvOnDemand()
	case 0x0500:
		c.onRecvVehiCtrl()
	case 0x0704:
		c.onRecvLoStatusBulk()
	case 0x0800:
		c.onRecvMediaEvent()
	case 0x1205:
		c.WriteAck(0)
		c.onRecvQueryResult()
	case 0x1206:
		c.onRecvFtpResp()
	case 0x1003:
		c.onRecvAVProperty()
	case 0x1005:
		c.onRecvPassengerTraffic()
	default:
		log.Printf("code 0x%04x, body length %d\n", c.Msg.ID, len(c.Msg.Data))
	}
	return p0 + 1, err
}

func (c *Client) OnIdle(rect, sendt *time.Time) error {
	return nil
}

// Request 发送请求
func (c *Client) Request(cmd xproto.ReqCode, s interface{}, r interface{}) error {
	key, err := uint16(0), error(nil)
	switch cmd {
	case xproto.ReqQuery:
		key, err = c.doQuery(s)
	case xproto.ReqParameters:
		key, err = c.doParameters(s)
	case xproto.ReqLiveStream:
		key, err = c.doLiveStream(s)
	case xproto.ReqPlayback:
		key, err = c.doPlayback(s)
	case xproto.ReqFileTransfer:
		key, err = c.doFileTransfer(s)
	case xproto.ReqFtpTransfer:
		key, err = c.doFtpTransfer(s)
	case xproto.ReqControl:
		key, err = c.doControl(s)
	case xproto.ReqVoice:
		key, err = c.doVoice(s)
	case xproto.ReqUser:
		key, err = c.doUser(s)
	case xproto.ReqClose:
		c.Conn.Close()
		return nil
	}
	if err != nil {
		return err
	}
	// log.Printf("Request sequence %d\n", key)
	return c.WaitVal(c.resultKey(key), r)
}
